if GLOBAL.TheNet:IsDedicated() or GLOBAL.TheNet:GetServerGameMode() == "lavaarena" then return end
-- if not GLOBAL.TheNet:GetIsClient() then return end
-- 上次游玩时间, 总游玩时间, 世界ID, [世界名称, IP, 端口, 密码]
local ent_util = require("libs/entutil")
local t_util = require("libs/tableutil")
local p_util = require "libs/playerutil"
local INV_PREFIX = "inv_"
local WORLD_PREFIX = "w_"
local NOTE_PREFIX = "v_"
local BUNDLE_PREFIX = "b_"
local AI_PREFIX = "ai_"

local note = "hx_note"
local idea = "hx_idea"
local png = "hx_png"

local baton,sticker,ai
local color_r,color_g,color_b,color_n  = 0, 1, 0, 1
-- a:all_time   总游玩时间
-- e:en_time    进入世界的时间
-- color_b:bind_file  绑定的文件序号
local box_data = {}

local profile_show_smart_minisign = "SHOW_SMART_MINISIGN"


local show_smart_minisign = true
local show_note_name = GetModConfigData("wanda_rename")
local show_item_highlight = GetModConfigData("sw_box")
local sw_minisign = GetModConfigData("sw_minisign")
-- 兼容旧版本
GLOBAL.PLAYERCOLOURS.WHITE = {1,1,1,1}
if GLOBAL.PLAYERCOLOURS[show_item_highlight] then
    color_r, color_g, color_b, color_n = GLOBAL.unpack(GLOBAL.PLAYERCOLOURS[show_item_highlight])
end
local has_insight_mod = HasModName("insight")
local enable_show_mod = IsInMODlist({"信息显示", "showme", "insight", "提示语句", "疼的放大镜"})
local show_bundle_content = GetModConfigData("sw_bundle") and not enable_show_mod


local table_show_huxi_sign = {"treasurechest", "dragonflychest",
    "medal_livingroot_chest", -- 勋章 树根宝箱
    "sora2chest_build_sora",  -- 强迫症箱子 
}
if sw_minisign == "more" then
    table.insert(table_show_huxi_sign, "icebox")
    table.insert(table_show_huxi_sign, "saltbox")
end
local table_show_note_name = {"pocketwatch_recall", "pocketwatch_portal"}
local table_shadow_container = {"shadow_container"}
local table_show_bundle_content = {"bundle", "gift"}
local table_chester_container = {"chester", "hutch"}


local function CanEnableMinisign()
    return not HasModName("小木牌") and not HasModName("minisign") and sw_minisign
end

-- 深度优先
local function PathRecursiver(searchBox, missingItem, path)
    if searchBox and searchBox == missingItem then
        return path
    end
    local container = ent_util:GetContainer(searchBox)
    if container then
        local items = container:GetItems() or {}
        local new_path
        for slot, item in pairs(items)do
            local new_path = path and PathRecursiver(item, missingItem, path..slot)
            if new_path then
                return new_path
            end
        end
    end
end


local function GetEntPosID(inst)
    if type(inst) == "table" then
        local prefab_name = inst.prefab
        if table.contains(table_shadow_container, prefab_name) then
            return WORLD_PREFIX.."sc"
        elseif table.contains(table_chester_container, prefab_name) then
            return WORLD_PREFIX..prefab_name
        end
    end
    if not ent_util:IsValid(inst) then return end

    local path
    if not inst:HasTag("INLIMBO") and not inst:HasTag("player") then
        local x,y,z = inst.Transform:GetWorldPosition()
        path = WORLD_PREFIX..string.format("%.2f_%.2f", x, z)
    else
        path = PathRecursiver(GLOBAL.ThePlayer, inst, INV_PREFIX)
        if not path then
            for _,equipslot in pairs(GLOBAL.EQUIPSLOTS or {})do
                path = PathRecursiver(GetEquippedItemFrom(equipslot), inst, INV_PREFIX..equipslot)
                if path then break end
            end
        end
        if not path then
            local inv =  GLOBAL.ThePlayer and GLOBAL.ThePlayer.replica and GLOBAL.ThePlayer.replica.inventory
            if inv then
                for container,stat in pairs(inv:GetOpenContainers()) do
                    if stat and not container:HasTag("INLIMBO") then
                        path = PathRecursiver(container, inst, GetEntPosID(container))
                        if path then break end
                    end
                end
            end
        end
    end
    return path
end



-----  智能小木牌
local function ShowSmartMinisign(ent)
    if not show_smart_minisign or (GLOBAL.TheWorld and GLOBAL.TheWorld.ismastersim) then return end
    if not table.contains(table_show_huxi_sign, ent.prefab) then
        return
    end
    local container = ent_util:GetContainer(ent)
    if not ent_util:IsValid(ent) or not container then return end

    local first_item = t_util:GetMinValue(container:GetItems())
    local f_data = first_item and first_item[png]
    local atlas, image
    if type(f_data) == "table" and f_data.a and f_data.i then
        atlas = f_data.a
        image = f_data.i
    else
        atlas, image = ent_util:GetAtlasAndImage(first_item)
    end
    if not atlas or not image then
        local posid = GetEntPosID(ent)
        local container_data = posid and box_data[posid]
        if container_data then
            atlas = container_data.sa
            image = container_data.si
            local num = container:GetNumSlots()
            if type(num) == "number" then
                for i=1,num do
                    local ai = container_data[AI_PREFIX..i]
                    if container_data[GLOBAL.tostring(i)] then
                        if table.contains(table_show_bundle_content ,container_data[GLOBAL.tostring(i)]) 
                            and type(ai)=="table" then
                            atlas = ai.a
                            image = ai.i
                        else
                        end
                        break
                    end
                end
            end
        end
    end

    local sign = ent.huxi_sign
    if not sign or not sign:IsValid() then
        sign = GLOBAL.SpawnPrefab("huxi_sign")
        sign.entity:SetParent(ent.entity)
        ent.huxi_sign = sign
        if ent.prefab == "dragonflychest" then
            sign.Transform:SetScale(1.2, 1.2, 1)
        end
    end
    sign:draw(atlas, image)
end


local function SwitchShowSmartMinisign()
    if not CanEnableMinisign() then
        TIP("智能小木牌", "red", "无法启用, 原因：启用了服务器版本的智能小木牌", "chat")
        return
    end
    if GLOBAL.TheWorld and GLOBAL.TheWorld.ismastersim then
        TIP("智能小木牌", "red", "无法启用, 原因：该功能不支持无洞穴世界", "chat")
        return
    end
    show_smart_minisign = not show_smart_minisign
    if show_smart_minisign then
        for _, ent in pairs(PlayerFindEnts())do
            ShowSmartMinisign(ent)
        end
    else
        for _, ent in pairs(PlayerFindEnts(nil, {"sign", "huxi", 
        -- "FX"         按下不表
    },{}))do
            ent:Remove()
        end
    end
    SaveModData(profile_show_smart_minisign, show_smart_minisign)
    TIP("智能小木牌", "white", show_smart_minisign)
end

if sw_minisign then
    DEAR_BTNS:AddDearBtn(GLOBAL.GetInventoryItemAtlas("minisign_picketwhite_drawn.tex"), "minisign_picketwhite_drawn.tex", "智能小木牌", "慕斯专享功能, 点击可选择不显示木牌或显示木牌", true, SwitchShowSmartMinisign)
end
-- AddBindBtn("sw_minisign", SwitchShowSmartMinisign)


-- 旺达表命名
local function SayMyName(inst, name, id)
    if ent_util:IsValid(inst) and type(name) == "string" then
        local strs = ""
        if inst.prefab then
            strs = GLOBAL.STRINGS.NAMES[string.upper(inst.prefab)]
            if strs and string.len(name) ~= 0  then               
                inst.name = strs.."["..name.."]"
                inst[id] = name
            end
        end
    end
end
local function SetMyAI(ent, ai, png)
    if ent_util:IsValid(ent) and type(ai) == "table" and ai.a and ai.i then
        ent[png] = ai
    end
end

local function HoldTheName(_, data)
    if data and data.item then
        if baton and table.contains(table_show_note_name, data.item.prefab) and not data.item[note] then
            SayMyName(data.item, baton, note)
        end
        baton = nil
        if table.contains(table_show_bundle_content, data.item.prefab) then
            if sticker then
                SayMyName(data.item, sticker, idea)
            end
            if ai then
                SetMyAI(data.item, ai, png)
            end
        end
        sticker = nil
        ai = nil
    end
end

local function ShowNoteName(ent)
    if not show_note_name then return end
    local container = ent_util:GetContainer(ent)
    local posid = GetEntPosID(ent)
    if posid and container then
        for slot, item in pairs(container:GetItems())do
            if table.contains(table_show_note_name, item.prefab) then
                local item_data = box_data[posid]
                if item_data then
                    SayMyName(item, item_data[NOTE_PREFIX..slot], note)
                end
            end
        end
    end
end
if show_note_name then
    for _,watch_name in pairs(table_show_note_name)do
        AddPrefabPostInit(watch_name, function(inst)
            inst:DoTaskInTime(0.5, function(inst)
                local posid = GetEntPosID(inst)
                if posid and not inst:HasTag("INLIMBO") and type(box_data) == "table" then
                    local item_data = box_data[posid]
                    if item_data then
                        SayMyName(inst, item_data[NOTE_PREFIX], note)
                    end
                end
            end)
    
            
            -- 一个小bug：丢在刷新区域却通过服务器离开会丢失数据
            inst:ListenForEvent("onremove", function(inst)
                local posid = GetEntPosID(inst)
                local name = inst[note]
                if name then
                    if posid and type(box_data) == "table" and not inst:HasTag("INLIMBO") then
                        box_data[posid] = {
                            [NOTE_PREFIX] = name
                        }
                    else
                        baton = name
                        GLOBAL.TheGlobalInstance:DoTaskInTime(0.3, function()
                            baton = nil
                        end)
                    end
                end
            end)
        end)
    end
end

-- 打包纸记忆（其实就是旺达表命名，不过不提供自己改备注的接口
local function ShowBundleContent(ent)
    if not show_bundle_content then return end
    local container = ent_util:GetContainer(ent)
    local posid = GetEntPosID(ent)
    if posid and container then
        for slot, item in pairs(container:GetItems())do
            if table.contains(table_show_bundle_content, item.prefab) then
                local item_data = box_data[posid]
                if item_data then
                    SayMyName(item, item_data[BUNDLE_PREFIX..slot], idea)
                    SetMyAI(item, item_data[AI_PREFIX..slot], png)
                end
            end
        end
    end
end


if show_bundle_content then
    local __ConfirmExecutionOnceTheLock
    AddClassPostConstruct("screens/playerhud", function(self)
        local __OpenContainer = self.OpenContainer
        self.OpenContainer = function(HUD, ent, ...)
            __OpenContainer(HUD, ent, ...)
            if __ConfirmExecutionOnceTheLock or (GLOBAL.TheWorld and GLOBAL.TheWorld.ismastersim) then return end
            local container = ent_util:GetContainer(ent)
            if container and ent:HasTag("bundle") then
                local widget = container:GetWidget()
                local _fn = widget and widget.buttoninfo and widget.buttoninfo.fn
                if _fn then
                    __ConfirmExecutionOnceTheLock = true
                    widget.buttoninfo.fn = function(ent, ...)
                        container = ent_util:GetContainer(ent)
                        if container then
                            local items = container:GetItems() or {}

                            ai = {}
                            ai.a, ai.i = ent_util:GetAtlasAndImage(t_util:GetMinValue(items))
                            if not ai.a or not ai.i then
                                ai = nil
                            end
                            local sticker_table = {}
                            for _, item in pairs(items)do
                                local name = item:GetBasicDisplayName()
                                local stacksize = ent_util:GetStacksize(item)
                                local perc = GetPerc(item)
                                if perc < 98 then
                                    name = name.."("..perc.."%)"
                                end 
                                if stacksize == 1 then
                                    table.insert(sticker_table, name)
                                else
                                    table.insert(sticker_table, name.."(".. stacksize .."个)")
                                end
                            end
                            sticker = table.concat(sticker_table,",")
                            GLOBAL.ThePlayer:DoTaskInTime(3, function()
                                sticker = nil
                                ai = nil
                            end)
                        end
                        _fn(ent, ...)
                    end
                end
            end
        end
    end)

    for _,bundle_name in pairs(table_show_bundle_content)do
        AddPrefabPostInit(bundle_name, function(inst)
            inst:DoTaskInTime(0.5, function(inst)
                local posid = GetEntPosID(inst)
                if posid and not inst:HasTag("INLIMBO") and type(box_data) == "table" then
                    local item_data = box_data[posid]
                    if item_data then
                        SayMyName(inst, item_data[BUNDLE_PREFIX], idea)
                        SetMyAI(inst, item_data[AI_PREFIX], png)
                    end
                end
            end)
    
            
            inst:ListenForEvent("onremove", function(inst)
                local posid = GetEntPosID(inst)
                local name = inst[idea]
                local ai = inst[png]
                if name and posid and type(box_data) == "table" and not inst:HasTag("INLIMBO") then
                    box_data[posid] = {
                        [BUNDLE_PREFIX] = name,
                        [AI_PREFIX] = ai
                    }
                end
            end)
        end)
    end
end







-- 核心
local function ContainerPostConstruct(self, ent)
    if not self.type and not self.__ConfirmToInitializeTheLock then
        self.__ConfirmToInitializeTheLock = true

        if ent and ent.OnEntityReplicated then
            local _OnEntityReplicated = ent.OnEntityReplicated
            ent.OnEntityReplicated = function(...)
                _OnEntityReplicated(...)
                ContainerPostConstruct(self, ent)
            end
        end
    end

    self.hx_record_data = function()
        -- print("startsave")
        local posid = GetEntPosID(ent)
        if not posid then 
            return
        elseif self:IsEmpty() or self:GetNumSlots()<5 then
            box_data[posid] = nil
            return 
        end

        local items = self:GetItems()

        if type(items) ~= "table" or not self.opener or not self.classified then print("失败", posid, self.opener, self.classified) return end

        local container_data = {
            f = self:IsFull() and 1 or 0
        }

        if table.contains(table_show_huxi_sign, ent.prefab) and not posid:starts(INV_PREFIX) then
            container_data.sa, container_data.si = ent_util:GetAtlasAndImage(t_util:GetMinValue(items))
        end


        for slot,item in pairs(items)do
            container_data[slot] = item.prefab
            container_data[NOTE_PREFIX..slot] = item[note]
            container_data[BUNDLE_PREFIX..slot] = item[idea]
            container_data[AI_PREFIX..slot] = item[png]
        end
        
        
        box_data[posid] = container_data
    end


    -- local _DetachClassified = self.DetachClassified
    -- self.DetachClassified = function(self, ...)
    --     self.hx_record_data()
    --     ShowSmartMinisign(ent)
    --     _DetachClassified(self, ...)
    -- end

    if show_note_name or show_bundle_content then
        local _Open = self.Open
        self.Open = function(self, ...)
            _Open(self, ...)
            ShowNoteName(ent)
            ShowBundleContent(ent)
        end
        self.inst:ListenForEvent("itemget", HoldTheName)
    end

    
    self.inst:ListenForEvent("itemget", self.hx_record_data)
    self.inst:ListenForEvent("itemlose", self.hx_record_data)

    
    -- if ent:HasOneOfTags({"backpack", "INLIMBO", "_equippable"}) then
        local _DetachOpener = self.DetachOpener
        self.DetachOpener = function(self, ...)
            self.hx_record_data()
            ShowSmartMinisign(ent)
            _DetachOpener(self, ...)
        end
        -- return
    -- end


    if table.contains(table_show_huxi_sign, ent.prefab) then
        local __Open = self.Open
        self.Open = function(self, ...)
            __Open(self, ...)
            ShowSmartMinisign(ent)
        end

        self.inst:ListenForEvent("itemget", ShowSmartMinisign)
        self.inst:ListenForEvent("itemlose", ShowSmartMinisign)
        ent:DoTaskInTime(0.5, ShowSmartMinisign)
    end
end

local function InventoryPostConstruct(self, ent)
    if not self.type and not self.__ConfirmToInitializeTheLock then
        self.__ConfirmToInitializeTheLock = true

        if ent and ent.OnEntityReplicated then
            local _OnEntityReplicated = ent.OnEntityReplicated
            ent.OnEntityReplicated = function(...)
                _OnEntityReplicated(...)
                InventoryPostConstruct(self, ent)
            end
        end
    end

    self.hx_record_data = function()
        local posid = GetEntPosID(ent)
        if not posid then return end

        local items = self:GetItems() or {}
        local inv_data = {}
        for slot,item in pairs(items)do
            inv_data[NOTE_PREFIX..slot] = item[note]
            inv_data[BUNDLE_PREFIX..slot] = item[idea]
            inv_data[AI_PREFIX..slot] = item[png]
        end
        
        
        box_data[posid] = inv_data
    end

    if show_note_name or show_bundle_content then
        local __DetachClassified = self.DetachClassified
        self.DetachClassified = function(self, ...)
            self.hx_record_data()
            __DetachClassified(self, ...)
        end
        self.inst:ListenForEvent("itemget", HoldTheName)
    end
end


if GLOBAL.TheNet:GetIsClient() then
    AddClassPostConstruct("components/container_replica", ContainerPostConstruct)
    AddClassPostConstruct("components/inventory_replica", InventoryPostConstruct)
    -- 算了，先禁了无洞穴模式
-- else
--     -- 无洞穴模式性能很差
--     AddPrefabPostInitAny(function(inst)
--         if inst.components and inst.components.container then
--             ContainerPostConstruct(inst.components.container)
--         end
--     end)
--     AddPrefabPostInit("world", function(world)
--         world:ListenForEvent("playeractivated", function(world, player)
--             if player == GLOBAL.ThePlayer then
--                 if player.components and player.components.inventory then
--                     InventoryPostConstruct(player.components.inventory)
--                 end
--             end
--         end)
--     end)
end




local function recordSurroundingData()
    if show_note_name or show_bundle_content then
        local inv = GLOBAL.ThePlayer and GLOBAL.ThePlayer.replica and GLOBAL.ThePlayer.replica.inventory
        if inv and inv.hx_record_data then inv:hx_record_data() end


        local ents = PlayerFindEnts()
        for _, ent in pairs(ents)do
            if table.contains(table_show_bundle_content, ent.prefab)
            or table.contains(table_show_note_name, ent.prefab) then
                local posid = GetEntPosID(ent)
                if posid then
                    box_data[posid] = {
                        [NOTE_PREFIX] = ent[note],
                        [BUNDLE_PREFIX] = ent[idea],
                        [AI_PREFIX] = ent[png]
                    }
                end
            end
        end
    end
end



local dyeing_containers = {}
local function ModifyContainerColor(container, reset, full, mult, add)
    if container and container.AnimState then
        if reset then
            container.AnimState:SetMultColour(1,1,1,1)
            container.AnimState:SetAddColour(0,0,0,1)
        else
            if mult or add then
                if mult then
                    container.AnimState:SetMultColour(mult[1], mult[2], mult[3], mult[4])
                end
                if add then
                    container.AnimState:SetAddColour(add[1], add[2], add[3], add[4])
                end
            else
                if full then
                    container.AnimState:SetMultColour(1,0,1,1)
                else
                    container.AnimState:SetMultColour(color_r,color_g,color_b,color_n)
                end
            end
            table.insert(dyeing_containers, container)
        end
    end
end

local coastline = {}
local tile_data = {}
local turf_size = 4
local turf_grid_radius = 10
local tile_ocean_shore = {GLOBAL.GROUND.OCEAN_START, GLOBAL.GROUND.OCEAN_COASTAL, GLOBAL.GROUND.OCEAN_COASTAL_SHORE}

local function ClearAllContainersColor()
    for _, dye_cont in pairs(dyeing_containers)do
        ModifyContainerColor(dye_cont, true)
    end
    dyeing_containers = {}

    
    for _, line in pairs(coastline) do
        if line and line.Remove then
            line:Remove()
        end
    end
    coastline = {}
end

local show_range_for_player = 60
local function ShowMeetContainersWithPrefab(prefab)
    ClearAllContainersColor()
    -- 如果没开高亮提示类的mod，就立即响应
    if show_item_highlight then
        if not enable_show_mod then
            local container_ents = PlayerFindEnts(36) -- {"_container", "chest", "structure"}
            for _, container_ent in pairs(container_ents)do
                local posid = GetEntPosID(container_ent)
                local data = posid and box_data[posid]
                if type(data) == "table" then
                    for _,thing in pairs(data)do
                        if thing == prefab then
                            if data.f == 1 then
                                ModifyContainerColor(container_ent, false, true)
                                ModifyContainerColor(container_ent.huxi_sign, false, true)
                            else
                                ModifyContainerColor(container_ent)
                                ModifyContainerColor(container_ent.huxi_sign)
                            end
                            break
                        end
                    end
                end
                if container_ent.prefab == prefab then
                    ModifyContainerColor(container_ent, false, false, {color_r, color_g, color_b, color_n}, {color_r, color_g, color_b, color_n})
                end
            end
        else
            -- 无法判断和其他高亮mod的优先加载顺序，所以礼让一下
            GLOBAL.TheGlobalInstance:DoTaskInTime(0.1, function(self)
                local container_ents = PlayerFindEnts(36)
                for _, container_ent in pairs(container_ents)do
                    if container_ent:HasTag("_container") and container_ent.AnimState then
                        local ra,ga,ba,ia =  container_ent.AnimState:GetAddColour()
                        local rm,gm,bm,im = container_ent.AnimState:GetMultColour()
                        if ra~=0 or ga~=0 or ba~=0 or rm~=1 or gm~=1 or bm~=1 
                        -- or im~=1 or ia~=0 
                        then
                            ModifyContainerColor(container_ent.huxi_sign, false, false, {rm,gm,bm,im}, {ra,ga,ba,ia})
                        end
                    elseif not has_insight_mod and container_ent.prefab == prefab then
                        ModifyContainerColor(container_ent, false, false, {color_r, color_g, color_b, color_n}, {color_r, color_g, color_b, color_n})
                    end
                end
            end)
        end
    end
    
    -- 显示海岸线
    if prefab == "dock_kit" then
        local map = GLOBAL.TheWorld.Map

        local center_x, _, center_z = map:GetTileCenterPoint(GLOBAL.ThePlayer.Transform:GetWorldPosition())
        local radius = turf_grid_radius * turf_size
        local count = 0

        for x = center_x - radius, center_x + radius + turf_size, turf_size do
            for z = center_z - radius, center_z + radius + turf_size, turf_size do
                tile_data[count] = map:GetTileAtPoint(x, 0, z)
                count = count+1
            end
        end

        for _, line in pairs(coastline) do
            if line and line.Remove then
                line:Remove()
            end
        end
        coastline = {}
        count = 0
        local z_num = 2*(turf_grid_radius+1)
        for x = 0, z_num-2, 1 do
            for z = 0, z_num-2, 1 do
                local c_id = z + z_num*x
                local pos_x = center_x + turf_size*(x - turf_grid_radius)
                local pos_z = center_z + turf_size*(z - turf_grid_radius)
                local diff_flag = table.contains(tile_ocean_shore, tile_data[c_id])
                local r_flag = table.contains(tile_ocean_shore, tile_data[c_id+1])
                local d_flag = table.contains(tile_ocean_shore, tile_data[c_id+z_num])
                if (diff_flag and {not r_flag} or {r_flag})[1] then
                    coastline[count] = GLOBAL.SpawnPrefab("hline")
                    coastline[count].Transform:SetPosition(pos_x, 0, pos_z+0.5*turf_size)
                    coastline[count].Transform:SetRotation(90)
                    count = count + 1
                end
                if (diff_flag and {not d_flag} or {d_flag})[1]   then
                    coastline[count] = GLOBAL.SpawnPrefab("hline")
                    coastline[count].Transform:SetPosition(pos_x+0.5*turf_size, 0, pos_z)
                    count = count + 1
                end
            end
        end
    end
end


local __ConfirmPlayerInitializationTheLock
AddPlayerActivatedFunc(function(player, world)
    player:ListenForEvent("newactiveitem", function()
        if player.replica.inventory then
            local active_item = GetActiveItem()
            if active_item then
                ShowMeetContainersWithPrefab(active_item.prefab)
            else
                ClearAllContainersColor()
            end
        end
    end)
    if __ConfirmPlayerInitializationTheLock then
        return
    end
    __ConfirmPlayerInitializationTheLock = true
    WORLD_PREFIX = world:HasTag("cave") and "c_" or "w_"
    local w_util = require "libs/worldmanager"
    box_data = w_util:GetWorldDataMap("box_memory")
    
    ShowNoteName(player)
    ShowBundleContent(player)
    w_util:AddPlayerLeaveFunc(recordSurroundingData)
    local result = LoadModData(profile_show_smart_minisign)
    show_smart_minisign = (type(result) == "nil" or result) and CanEnableMinisign()
end)

-- 我抄我自己

local sw_rename = false
local funcTip = "旺达表命名"

local function AdaptTIP(sw)
    if sw then
        TIP(funcTip, "yellow", "已开启, 右键单击 溯源表或裂缝表 进行命名或重命名", "chat")
    else
        TIP(funcTip, "red", "已关闭", "chat")
    end
end

local writeablescreen
local WriteableWidget = require "screens/TMIP_writeablewidget"
local writeable_widget_args = {
    animbank = "ui_board_5x3",
    animbuild = "ui_board_5x3",
    menuoffset = GLOBAL.Vector3(6, -70, 0),
    cancelbtn = {
        text = GLOBAL.STRINGS.UI.TRADESCREEN.CANCEL,
        cb = function()
            GLOBAL.ChatHistory:AddToHistory(GLOBAL.ChatTypes.Message, nil, nil, funcTip, "取消", GLOBAL.PLAYERCOLOURS.YELLOW)
        end,
        control = GLOBAL.CONTROL_CANCEL
    },
    acceptbtn = {
        text = GLOBAL.STRINGS.UI.TRADESCREEN.ACCEPT,
        cb = function(w, target)
            SayMyName(target, w:GetText(), note)
        end,
        control = GLOBAL.CONTROL_ACCEPT
    }
}
local function OpenWriteScreen(target)
    if writeablescreen then
        writeablescreen:KillAllChildren()
        writeablescreen:Kill()
        writeablescreen = nil
    end
    writeablescreen = WriteableWidget(writeable_widget_args, target)
    GLOBAL.ThePlayer.HUD:OpenScreenUnderPause(writeablescreen)
    if GLOBAL.TheFrontEnd:GetActiveScreen() == writeablescreen then
        writeablescreen.edit_text:SetEditing(true)
    end
end

local function SwitchShowNoteName()
    if GLOBAL.TheWorld and GLOBAL.TheWorld.ismastersim then
        return TIP(funcTip, "red", "无法启用, 原因：该功能不支持无洞穴世界", "chat")
    end
    sw_rename = not sw_rename
    AdaptTIP(sw_rename)
end
if GetModConfigData("wanda_rename") == "biubiu" then
DEAR_BTNS:AddDearBtn(GLOBAL.GetInventoryItemAtlas("pocketwatch_recall.tex"), "pocketwatch_recall.tex", funcTip, "我丢你老表啊~~", true, SwitchShowNoteName)
end
AddBindBtn("wanda_rename", SwitchShowNoteName)

AddClassPostConstruct("widgets/invslot", function(self)
    local _OnControl = self.OnControl
    self.OnControl = function(self, control, down, ...)
        if down and control == GLOBAL.CONTROL_SECONDARY and not GLOBAL.TheInput:IsControlPressed(GLOBAL.CONTROL_FORCE_TRADE) 
        and sw_rename 
        and self.tile and self.tile.item and table.contains(table_show_note_name, self.tile.item.prefab)
        then
            OpenWriteScreen(self.tile.item)
            sw_rename = false
        else
            return _OnControl(self, control, down, ...)
        end
    end
end)


-- 更改显示
local str_rename = GLOBAL.STRINGS.KITCOON_NAMING.MENU_ACCEPT
local str_re_rename = GLOBAL.STRINGS.ACTIONS.RESETMINE..str_rename
AddComponentPostInit("playeractionpicker", function(self)
    local _GetInventoryActions = self.GetInventoryActions
    self.GetInventoryActions = function(self, item, ...)
        local inv_actions = _GetInventoryActions(self, item, ...)
        if sw_rename and table.contains(table_show_note_name, item.prefab) then
            for _, inv_action in pairs(inv_actions) do
                if inv_action.action == GLOBAL.ACTIONS.LOOKAT or inv_action.action == GLOBAL.ACTIONS.CAST_POCKETWATCH then
                    if item[note] then
                        inv_action.GetActionString = function()
                            return str_re_rename
                        end
                    else
                        inv_action.GetActionString = function()
                            return str_rename
                        end
                    end
                end
            end
        end
        return inv_actions
    end
end)



local pointer
-- is_display
---- true:展示该prefab
---- false:移除该prefab的展示
local function ShowPrefabView(prefab, is_display)
    if not prefab then
        return
    end
    if is_display then
        pointer = prefab
    else
        if pointer == prefab then
            pointer = nil
        end
    end
    ShowMeetContainersWithPrefab(pointer)
end

local function ClickEntity(ent)
    local function Click()
        if ent_util:IsValid(ent) then
            local picker = GLOBAL.ThePlayer and GLOBAL.ThePlayer.components.playeractionpicker
            local pos = ent:GetPosition()
            local right = ent.prefab == "bookstation"
            if (ent.prefab == "beefalo" or ent == GLOBAL.ThePlayer) and picker then
                local _, beef_act = GLOBAL.next(picker:GetRightClickActions(pos, ent))
                if beef_act._lock_huxi_dont_toss then
                    local equip = GetEquippedItemFrom("hands")
                    if equip:HasTag("dumbbell") then
                        GLOBAL.ThePlayer.replica.inventory:ControllerUseItemOnSelfFromInvTile(equip)
                    end
                end
                local beef_action = beef_act and beef_act.action
                right = beef_action and  table.contains({"DISMOUNT", "MOUNT"}, beef_action.id)
            end
            if pos and picker then
                local _, lftclk_act 
                if right then
                    _, lftclk_act  = GLOBAL.next(picker:GetRightClickActions(pos, ent))
                else
                    _, lftclk_act  = GLOBAL.next(picker:GetLeftClickActions(pos, ent))
                end
                local act = lftclk_act and lftclk_act.action
                if (act and table.contains({"LOOKAT", "CASTSPELL"}, act.id)) or (not act) then
                    lftclk_act = GLOBAL.BufferedAction(GLOBAL.ThePlayer, ent, GLOBAL.ACTIONS.WALKTO, nil, pos)
                    act = GLOBAL.ACTIONS.WALKTO
                    ent = GetActiveItem() and ent or nil
                    right = false
                end
                    -- local buff_act = GLOBAL.BufferedAction(GLOBAL.ThePlayer, ent, act, nil, pos)
                local controller = GLOBAL.ThePlayer and GLOBAL.ThePlayer.components.playercontroller
                lftclk_act.preview_cb = function()
                    GLOBAL.SendRPCToServer(right and GLOBAL.RPC.RightClick or GLOBAL.RPC.LeftClick, act.code, pos.x,pos.z, ent, nil, nil, not right, nil, lftclk_act.mod_name, false)
                end
                if controller.locomotor then
                    controller:DoAction(lftclk_act)
                else
                    lftclk_act.preview_cb()
                end
                local str = type(act.str) == "table" and act.str.GENERIC or (type (act.str) == "string" and act.str or "点击")
                return type(str) == "string" and str or "点击"
            end
        end
    end
    local re = Click()
    GLOBAL.ThePlayer:DoTaskInTime(0, Click)     -- 解决过远时无法生效的问题？
    return re
end

local function SearchContainerWithPrefab(prefab)
    local container_finds = ent_util:FindEnts(nil, nil, nil, {"_container"},{'FX','DECOR','INLIMBO','NOCLICK', 'player','stewer','backpack','trader','lamp'}, nil, nil, function(ent)
        return table.contains(p_util:GetActionIDs(ent), "RUMMAGE")
    end)
    for _, container_ent in pairs(container_finds)do
        local posid = GetEntPosID(container_ent)
        local data = posid and box_data[posid]
        local con_rep = ent_util:GetContainer(container_ent)
        if type(data) == "table" and con_rep and con_rep:GetNumSlots() > 5 then
            for _,thing in pairs(data)do
                if thing == prefab then
                    return container_ent
                end
            end
        end
    end
end
GLOBAL.MOD_ShroomCake.SearchContainerWithPrefab = SearchContainerWithPrefab
local function GetContainerHasPrefab(prefab, all_mod)
    local container_finds = PlayerFindEnts(show_range_for_player, {"_container"},{'FX','DECOR','INLIMBO','NOCLICK', 'player','stewer','backpack','trader','lamp'})
    if enable_show_mod and all_mod then
        for _, container_ent in pairs(container_finds)do
            local con_rep = ent_util:GetContainer(container_ent)
            if container_ent.AnimState and con_rep and con_rep:GetNumSlots() > 5 then
                local ra,ga,ba,ia =  container_ent.AnimState:GetAddColour()
                local rm,gm,bm,im = container_ent.AnimState:GetMultColour()
                if ra~=0 or ga~=0 or ba~=0 or rm~=1 or gm~=1 or bm~=1 -- or im~=1 or ia~=1 
                then
                    return container_ent
                end
            end
        end
    else
        for _, container_ent in pairs(container_finds)do
            local posid = GetEntPosID(container_ent)
            local data = posid and box_data[posid]
            local con_rep = ent_util:GetContainer(container_ent)
            if type(data) == "table" and con_rep and con_rep:GetNumSlots() > 5 then
                for _,thing in pairs(data)do
                    if thing == prefab then
                        return container_ent
                    end
                end
            end
        end
    end
end
local function CanDoubleSearch(prefab)
    local R = GLOBAL.AllRecipes
    local ingrds = R and R[prefab] and R[prefab].ingredients
    return type(ingrds) == "table" and #ingrds == 1 and type(ingrds[1]) == "table" and ingrds[1].type
end
local function SearchPrefabWithClick(prefab, dad_name, time)
    if type(prefab)~="string" then
        return
    end
    -- 此处适配威尔逊
    local _prefab
    if string.sub(prefab, 1, 10) == "transmute_" then
        _prefab = prefab
        prefab = string.sub(prefab, 11)
    end
    local flag
    local item_name =  GLOBAL.STRINGS.NAMES[prefab:upper()] or "未知材料"
    local ent_find = PlayerFindEnt(prefab, show_range_for_player, nil, nil, nil, nil, not GLOBAL.ThePlayer:IsOnOcean(true))
    flag = ClickEntity(ent_find)
    if flag then
        flag = flag.." "..item_name
    else        
        local container = GetContainerHasPrefab(prefab, not dad_name)
        if container then
            local cont_name = container.name or "未知容器"
            flag = ClickEntity(container)
            flag = flag and flag.."有 "..item_name.. " 的" ..cont_name
        end
    end
    time = time or 0
    if not flag then
        local child = CanDoubleSearch(_prefab or prefab)
        if child and time<4 then
            item_name = type(dad_name) == "string" and dad_name.."->"..item_name or item_name
            return SearchPrefabWithClick(child, item_name, time+1)
        else
            TIP("我找不到", "red")
        end
    else
        flag = type(dad_name) == "string" and flag.."(制作 "..dad_name.." 的材料)" or flag
        TIP(flag, "white")
    end
    return flag
end

local enabled_middle  = GetModConfigData("sw_middle")
if enabled_middle and type(enabled_middle)=="boolean" then
    enabled_middle = GLOBAL.MOUSEBUTTON_MIDDLE -- 1002
end

AddClassPostConstruct("widgets/ingredientui", function (self, ...)
    local function getPrefab()
        return self.ing and self.ing.texture and self.ing.texture:match('[^/]+$'):gsub('%.tex$', '')
    end
    local _OnGainFocus = self.OnGainFocus
    function self.OnGainFocus(self, ...)
        ShowPrefabView(getPrefab(), true)
        if _OnGainFocus then
            return _OnGainFocus(self, ...)
        end
    end

    local _OnLoseFocus = self.OnLoseFocus
    function self.OnLoseFocus(self, ...)
        ShowPrefabView(getPrefab(), false)
        if _OnLoseFocus then
            return _OnLoseFocus(self, ...)
        end
    end
    
    if enabled_middle then
        local _OnMouseButton = self.OnMouseButton
        function self.OnMouseButton(self, button, down, ...)
            if button == enabled_middle and down then
                SearchPrefabWithClick(getPrefab())
            end
            return _OnMouseButton(self, button, down, ...)
        end
    end
end)

-- 侧边栏显示
AddClassPostConstruct("widgets/redux/craftingmenu_pinslot", function (self, ...)
    local _OnGainFocus = self.OnGainFocus
    function self.OnGainFocus(self, ...)
        ShowPrefabView(self.recipe_name, true)
        return _OnGainFocus(self, ...)
    end    
    
    local _OnLoseFocus = self.OnLoseFocus
    function self.OnLoseFocus(self, ...)
        ShowPrefabView(self.recipe_name, false)
        return _OnLoseFocus(self, ...)
    end

    if enabled_middle then
        local _OnMouseButton = self.OnMouseButton
        function self.OnMouseButton(self, button, down, ...)
            if button == enabled_middle and down then
                -- 目前没有服务器支持侧边栏高亮容器
                SearchPrefabWithClick(self.recipe_name, true)
            end
            return _OnMouseButton(self, button, down, ...)
        end
    end
end)

-----------------------勇敢牛牛，不怕困难------------------------------

if show_item_highlight then
    local mod_child = "_huxi_bind_beefalo"
    local function setDad(inst)
        local dad = GetLeader(inst)
        if dad then
            dad[mod_child] = inst
        end
    end
    AddPrefabPostInit("beefalo", function(inst)
        inst:DoTaskInTime(0.5, function()
            setDad(inst)
        end)
    end)
    AddClassPostConstruct("screens/playerhud", function(self)
        local __ShowWriteableWidget = self.ShowWriteableWidget
        self.ShowWriteableWidget = function(self, inst, ...)
            if inst and inst.prefab == "beefalo" then
                setDad(inst)
            end
            return __ShowWriteableWidget(self, inst, ...)
        end
    end)
    local beefs = {}
    AddHovererFuncAndIsOut(function(target, prefab)
        if type(target) == "table" and prefab == "beef_bell" then
            local beef = target[mod_child]
            if target == GetLeader(beef) then
                table.insert(beefs, beef)
                ModifyContainerColor(beef)
            end
        end
        AddHovererFuncAndIsOut(function(target, prefab)
            if #beefs ~= 0 then
                for _, beef in pairs(beefs) do
                    ModifyContainerColor(beef, true)
                end
                beefs = {}
            end
			RemoveHovererFuncAndIsOut(true, "_huxi_beef_addcolor")
        end, true, "_huxi_beef_addcolor")
    end)
end


-------------------------中键查找---------------------------------
if not enabled_middle then
    return
end


GLOBAL.MOD_ShroomCake.SearchPrefabWithClick = SearchPrefabWithClick
    

AddClassPostConstruct("widgets/redux/craftingmenu_hud", function(self, ...)
    local _OnMouseButton = self.OnMouseButton

    function self.OnMouseButton(self, button, down, ...)
        if button == enabled_middle and down then
            if self.pinbar and self.pinbar and self.pinbar.open_menu_button and self.pinbar.open_menu_button.focus then
                local prefabs = {"dirtpile"}
                local des = "脚印"
                local adk = GLOBAL.MOD_ShroomCake and GLOBAL.MOD_ShroomCake.getAttackDistKey and GLOBAL.MOD_ShroomCake.getAttackDistKey()
                if adk == "seeds" then
                    table.insert(prefabs, adk)
                    des = "脚印或种子"
                end
                local ent = PlayerFindEnt(prefabs,show_range_for_player,nil,nil,nil,nil,true)
                if ent and ent:IsValid() then
                    local text = ClickEntity(ent)
                    if text then
                        TIP(text.." "..(type(ent.name) == "string" and ent.name or "未知实体"), "white")
                    end
                else
                    TIP("附近没有"..des, "white")
                end
                return _OnMouseButton(self, button, down, ...)
            end

            local menu = self.craftingmenu
            if menu then
                local grid = menu.recipe_grid
                local skin = menu.details_root and menu.details_root.skins_spinner
                local prefab
                -- 抄自己的快捷宣告喽
                if grid and grid.focus and grid.shown then
                    local index = grid.focused_widget_index +  grid.displayed_start_index
                    local items = grid.items
                    if index and items and items[index] then
                        local recipe = items[index].recipe
                        prefab = recipe and recipe.name
                    end
                elseif skin and skin.focus and skin.enabled and skin.shown then
                    prefab = skin.recipe and skin.recipe.name
                end
                -- showme这么拉吗
                SearchPrefabWithClick(prefab, true)
            end
            -- 不要补充了，menu此时已经执行过一次了
        end
        return _OnMouseButton(self, button, down, ...)
    end
end)

local put_thread
local items_task = {}
local id_memory = "MOD_THREAD_PUTITEM"
local function SetTint(item, toGreen)
    local image = item and item.hx_data and item.hx_data.t and item.hx_data.t.image
    if image then
        if toGreen then
            if item:HasTag("fresh")then
                image:SetTint(1,0,0,1)
            else
                image:SetTint(0,1,0,1)
            end
        else
            image:SetTint(1,1,1,1)
        end
    end
end
local container_file = require("containers")
local function TestPut(container, item, slot)
    local c_prefab = (type(container)=="table" and container.inst and container.inst.prefab) or (type(container)=="string" and container)
    if not c_prefab then
        return
    end
    local testfunc = container_file and container_file.params and container_file.params[c_prefab] 
        and type(container_file.params[c_prefab].itemtestfn) == "function"
        and container_file.params[c_prefab].itemtestfn
    if not testfunc then
        return true
    else
        return testfunc(container, item, slot)
    end
end
local function GetContainerHasPrefabAndNotFull(item)
    if not item then
        return
    end
    local prefab = item.prefab
    local bantags = {'FX','DECOR','INLIMBO','NOCLICK', 'player','stewer','backpack', 'trader', 'lamp'}
    
    
    local container_finds = PlayerFindEnts(show_range_for_player, {"_container"},bantags)

    local nil_b, nil_s, nil_f, nil_p = {},{},{},{}
    local has_b, has_s, has_f, has_p = {},{},{},{}
    for _, container_ent in pairs(container_finds)do
        local posid = GetEntPosID(container_ent)
        local data = posid and box_data[posid]
        local cont_rep = ent_util:GetContainer(container_ent)
        if (cont_rep and cont_rep:GetNumSlots() < 5) 
            or not container_ent:HasOneOfTags({"hutch", "chester", "structure"})
        then
            -- 排除容量小于5的容器
            -- 排除不是建筑、不是切斯特和哈奇的容器
        else
            if type(data) == "table" then
                if data.f == 1 then
                    -- 排除满了的容器
                else
                    for _,thing in pairs(data)do
                        -- 最优先寻找放了该物品但是没满的箱子
                        if thing == prefab then
                            return container_ent
                        end
                    end
                    -- 有特
                    if container_ent and container_ent.prefab == "bookstation" then
                        table.insert(has_b, container_ent)
                    elseif container_ent:HasTag("saltbox") then
                        table.insert(has_s, container_ent)
                    elseif container_ent:HasTag("fridge") then
                        table.insert(has_f, container_ent)
                    else
                    -- 有普
                        table.insert(has_p, container_ent)
                    end
                end
            elseif data == nil then
                -- 空特
                if container_ent and container_ent.prefab == "bookstation" then
                    table.insert(nil_b, container_ent)
                elseif container_ent:HasTag("saltbox") then
                    table.insert(nil_s, container_ent)
                elseif container_ent:HasTag("fridge") then
                    table.insert(nil_f, container_ent)
                else
                -- 空普
                    table.insert(nil_p, container_ent)
                end
            end
        end
    end

    
    -- 腐烂食物 空普 -》有普 -》空特 -》有特
    -- 食物和书 有特 -》空特 -》空普 -》有普
    -- 普通物品 空普 -》有普 （放不到特里的）
    local container_ents = {}
    if item:HasTag("fertilizer") then
        container_ents = mergeTable(nil_p, has_p, nil_f, nil_s, has_f, has_s)
    elseif TestPut("icebox", item) or TestPut("saltbox", item) or TestPut("bookstation", item) then
        container_ents = mergeTable(has_b, has_s, has_f, nil_b, nil_s, nil_f, nil_p, has_p)
    else
        container_ents = mergeTable(nil_p, has_p)
    end

    -- TestPut应该在准备放置的时候才去执行，这样省计算量
    for _, container_ent in pairs(container_ents)do
        -- 这里埋了个bug，希望以后不会触发，现在太懒了，懒得修
        if TestPut(ent_util:GetContainer(container_ent), item) then
            return container_ent
        end
    end
    print("未找到")
end
local function StopPutThread(message, col)
    GLOBAL.KillThreadsWithID(id_memory)
    put_thread = nil
    for _,item in pairs(items_task)do
        SetTint(item)
    end
    items_task = {}
    if message ~= "" then
        TIP(message or "收纳中断", col or "white") 
        if message then
            GLOBAL.TheFocalPoint.SoundEmitter:PlaySound("dontstarve/HUD/research_available")
        end
    end
end

local function IsOpeningContainer(container)
    if not container then return end
    local inv = GLOBAL.ThePlayer and GLOBAL.ThePlayer.replica.inventory
    if inv then
        for cont in pairs(inv:GetOpenContainers())do
            local con_rep = cont and cont.replica.container
            if container == cont and con_rep:IsOpenedBy(GLOBAL.ThePlayer) then
                return con_rep
            end
        end
    end
end
local last_click_time = 0
local last_click_tile
for _,classname in pairs({"invslot", --"equipslot" -- 暂时不支持身上的装备也自动收纳，或许以后会写？
}) do
	local SlotClass = require("widgets/"..classname)
	local SlotClass_omb = SlotClass.OnMouseButton
	function SlotClass:OnMouseButton(button, down, ...)
		if button == enabled_middle and self.tile and self.tile.item and down then
            if GLOBAL.TheWorld and GLOBAL.TheWorld.ismastersim then
                return TIP("中键加强", "red", "无法启用, 原因：该功能不支持无洞穴世界", "chat")
            end
            if #items_task == 0 and p_util:IsInBusy() then
                return TIP("中键加强", "red", "玩家正忙...")
            end
            if table.contains({"chester_eyebone", "hutch_fishbowl"}, self.tile.item.prefab) then
                local ent = PlayerFindEnt({"chester", "hutch"}, show_range_for_player, nil, nil, nil, nil, true)
                local prefab = ent and ent.prefab
                if prefab then
                    SearchPrefabWithClick(prefab)
                    return StopPutThread("")
                end
            elseif self.tile.item.prefab == "beef_bell" then
                local beefing = GLOBAL.ThePlayer and GLOBAL.ThePlayer.replica.rider and GLOBAL.ThePlayer.replica.rider.classified.ridermount:value()
                local ent
                if beefing then
                    ent = GLOBAL.ThePlayer
                else
                    ent = PlayerFindEnt("beefalo", show_range_for_player, nil, nil, nil, nil, true, function(beef)
                        return self.tile.item == GetLeader(beef)
                    end)
                end
                if ent and ent_util:IsValid(ent) then
                    local text = ClickEntity(ent)
                    if text then
                        TIP(text.." "..(type(ent.name) == "string" and ent.name or "未知实体"), "white")
                    end
                    return StopPutThread("")
                end
            else
                local data = {t = self.tile, i = self.tile.item, c = self.container, n = self.num}
                if GLOBAL.TheInput:IsKeyDown(GLOBAL.KEY_SHIFT) then
                    local now = GLOBAL.GetTime()
                    if (now - last_click_time < 0.3) and self.tile == last_click_tile then
                        if data.i.prefab then
                            local slots = p_util:GetPrefabSlotsWithInvAndBackPack(data.i.prefab)
                            for _,slot in ipairs(slots)do
                                local sdata = {t = slot.tile, i = slot.tile.item, c = slot.container, n = slot.num}
                                if not table.contains(items_task, sdata.i) then
                                    sdata.i.hx_data = sdata
                                    SetTint(sdata.i, true)
                                    table.insert(items_task, sdata.i)
                                end
                            end
                        end
                    else
                        if not table.contains(items_task, data.i) then
                            data.i.hx_data = data
                            SetTint(data.i, true)
                            table.insert(items_task, data.i)
                        end
                    end
                    last_click_time = now
                    last_click_tile = self.tile
                else
                    if not table.contains(items_task, data.i) then
                        data.i.hx_data = data
                        SetTint(data.i, true)
                        table.insert(items_task, data.i)
                    else
                        table.removetablevalue(items_task, data.i)
                        SetTint(data.i)
                    end
                end
                if not put_thread then
                    put_thread = GLOBAL.StartThread(function()
                        while put_thread do
                            local id, item = GLOBAL.next(items_task)
                            if id and item and item.hx_data then
                                local data = item.hx_data
                                if item:IsValid() and data.c then
                                    if data.c.inst and data.c.inst:HasOneOfTags({"player", "backpack"}) then
                                        local container = GetContainerHasPrefabAndNotFull(item)
                                        local container_rep = IsOpeningContainer(container)
                                        if container_rep then
                                            if container_rep:IsFull() then
                                            else
                                                repeat
                                                    data.c:MoveItemFromAllOfSlot(data.n,container)
                                                    GLOBAL.Sleep(GLOBAL.FRAMES*3)
                                                until item ~= data.c:GetItemInSlot(data.n)
                                                table.remove(items_task, id)
                                                SetTint(item)
                                            end
                                        else
                                            if container and container.Transform and container.name and ent_util:IsValid(container) then
                                                TIP((item.name or "").." 收纳进 "..container.name, "white")
                                                ClickEntity(container)
                                                repeat GLOBAL.Sleep(GLOBAL.FRAMES*3) until IsOpeningContainer(container)
                                            else
                                                TIP("无法收纳 "..(item.name or ""), "red")
                                                table.remove(items_task, id)
                                                SetTint(item)
                                            end
                                        end
                                    else
                                        local item_record = data.c:GetItemInSlot(data.n)
                                        if item_record == item then
                                            local inv = GLOBAL.ThePlayer and GLOBAL.ThePlayer.replica.inventory
                                            local equip = GetEquippedItemFrom("back") or GetEquippedItemFrom("body")
                                            local equiped = equip and equip:HasTag("backpack") and ent_util:GetContainer(equip)
                                            local container = (inv and (not inv:IsFull()) and GLOBAL.ThePlayer) or (equiped and (not equiped:IsFull()) and equip)
                                            if container and data.c.inst then
                                                data.c:MoveItemFromAllOfSlot(data.n,container)
                                                TIP("从 "..(data.c.inst.name or "未知容器").." 里拿走 "..(item.name or "未知物品"), "white")
                                            else
                                                StopPutThread("拿不下了", "red")
                                                break
                                            end
                                        else
                                            table.remove(items_task, id)
                                            SetTint(item)
                                        end
                                    end
                                    
                                else
                                    table.remove(items_task, id)
                                    SetTint(item)
                                end
                            else
                                StopPutThread("收纳结束", "red")
                                break
                            end
                            GLOBAL.Sleep(GLOBAL.FRAMES*3)
                        end
                    end, id_memory)
                else
                    --print("任务已开始")
                end
            end
		end
        return SlotClass_omb(self, button, down, ...)
	end
end
InterruptedByMobile(function() return put_thread end, StopPutThread)


-- 给群友零冲加的
GLOBAL.TheInput:AddMouseButtonHandler(function(button, down, x, y)
    if button == enabled_middle
    and not down 
    and ent_util:InGame()
    then
        -- print(GLOBAL.TheInput:GetHUDEntityUnderMouse())
        local ent = GLOBAL.TheInput:GetWorldEntityUnderMouse()
        if ent == GLOBAL.ThePlayer then
            if ent.replica.rider and ent.replica.rider.classified.ridermount:value() then
                local bell = p_util:GetItemFromAll("beef_bell")
                local t = 0
                if bell then
                    p_util:DropItemFromInvTile(bell)
                    t = 0.5
                end
                ent:DoTaskInTime(t, function()
                    p_util:ActClick(ent, "DISMOUNT" ,true)
                end)
            end
        end
    end
end)

-- local _SendRPCToServer = GLOBAL.SendRPCToServer
-- function GLOBAL.SendRPCToServer(...)
--     print(...)
--     _SendRPCToServer(...)
-- end